package com.xneure.code.log;

import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.xneure.code.CacheMap;
import com.xneure.code.intf.CacheEvent;
import com.xneure.code.log.ILog.Level;
import com.xneure.utils.ObjectUtil;
import com.xneure.utils.StackUtil;
import com.xneure.utils.bean.GUID;

public final class LogManage{
	private static Map<GUID,WeakReference<ILog>> currLog = new CacheMap<GUID,WeakReference<ILog>>(){
		private static final long serialVersionUID = 8134869378981495743L;
		{
			setCall(new CacheEvent<GUID,WeakReference<ILog>>(){
				@Override
				public boolean isExpire(Entry<GUID,WeakReference<ILog>> entry){
					return null == entry.getValue().get();
				}
			});
		}
	};
	private static Set<LogWatcher> watchers = new HashSet<LogWatcher>();
	private static ILog defLog = newLog();
	static SysPrintHandle err;
	static SysPrintHandle out;

	public static void monitorSystemOut(){
		synchronized(System.out){
			out = agentSysOut(System.out);
			err = agentSysOut(System.err);
		}
	}

	private static SysPrintHandle agentSysOut(OutputStream ps){
		ILog log = LogManage.newLog();
		OutputStream fieldValue = ObjectUtil.getFieldValue(ps,"out");
		while(fieldValue instanceof BufferedOutputStream == false){
			if(fieldValue instanceof SysPrintHandle){
				return null;
			}
			ps = fieldValue;
			fieldValue = ObjectUtil.getFieldValue(ps,"out");
		}
		SysPrintHandle soh = new SysPrintHandle(log,Level.DEBUG,fieldValue);
		ObjectUtil.modifyFieldValue(ps,"out",soh);
		return soh;
	}

	@Override
	protected void finalize() throws Throwable{
		super.finalize();
	}

	public static ILog getDefaultLog(){
		return defLog;
	}

	/**
	 * 创建一个日志处理器
	 * 
	 * @return ILog
	 */
	public static ILog newLog(){
		synchronized(currLog){
			PrintLog newLog = new PrintLog(StackUtil.getFirstCaller().getClassName());
			currLog.put(GUID.randomID(),new WeakReference<>(newLog));
			for(LogWatcher m:watchers){
				for(WeakReference<ILog> ent:currLog.values()){
					ILog iLog = ent.get();
					if(null != iLog){
						iLog.addWatcher(m);
					}
				}
			}
			return newLog;
		}
	}

	public static void registerLog(ILog log){
		synchronized(currLog){
			for(LogWatcher m:watchers){
				log.addWatcher(m);
			}
			currLog.put(GUID.randomID(),new WeakReference<>(log));
		}
	}

	/**
	 * 注册日志监视器，监视所有日志。
	 * 
	 * @param lw void
	 */
	public static void registerWatcher(LogWatcher lw){
		registerWatcher(null,lw);
	}

	/**
	 * 注册日志监视器，监视指定的日志对象，
	 * 
	 * @param cls 为null监视所有对象。
	 * @param lw void
	 */
	public static void registerWatcher(Class<? extends ILog> cls,LogWatcher lw){
		if(ObjectUtil.isContainNull(lw)){
			return;
		}
		if(watchers.contains(lw)){
			System.out.println(lw.getClass().getName() + " 重复注册。");
		}else{
			watchers.add(lw);
			Collection<WeakReference<ILog>> values = currLog.values();
			for(WeakReference<ILog> l:values){
				ILog iLog = l.get();
				if(null != iLog){
					if(null != cls && iLog.getClass().equals(cls)){
						iLog.addWatcher(lw);
					}else{
						iLog.addWatcher(lw);
					}
				}
			}
		}
	}

	public static void saveAllLog(){
		for(LogWatcher lw:watchers){
			lw.saveLog();
		}
	}

	public static void reset(){
		watchers.clear();
		currLog.clear();
	}
}
